; PlayIt veneers
; by Rick Hudson, (c) 1999
; assembles with asm
; this source uses AOF register bindings for sl,fp,ip,sp,lr,pc (ie R10-R15)
; but plain ol' r0-r9 for the rest since the SWIs are defined in terms of them
; and it's confusing when arranging registers to sometimes use r0-r3 and sometimes
; a1-a4. So it is avoided.
;
; all 'out' parameters (ie those for writing return values) are tested and only
; written if they are non-NULL
;
; If the SWI returns an error return is immediate with any return parameters
; undefined (specifically they are not changed).
;
; PlayIt needs to be loaded to assemble this for SWI name lookup

; It is TRULY unbelievable that ObjAsm cannot evaluate SWI numbers from strings.
; This duplication of data is completely ridiculous!

X_Bit			EQU	&20000

XPlayIt_Version		EQU	&4D140 + X_Bit
XPlayIt_Config		EQU	&4D141 + X_Bit
XPlayIt_LoadDriver	EQU	&4D142 + X_Bit
XPlayIt_DriverInfo	EQU	&4D143 + X_Bit
XPlayIt_SampleInfo	EQU	&4D144 + X_Bit
XPlayIt_Status		EQU	&4D145 + X_Bit
XPlayIt_Volume		EQU	&4D146 + X_Bit
XPlayIt_Open		EQU	&4D147 + X_Bit
XPlayIt_BeginEnd	EQU	&4D148 + X_Bit
XPlayIt_SetPtr		EQU	&4D149 + X_Bit
XPlayIt_Play		EQU	&4D14A + X_Bit
XPlayIt_Stop		EQU	&4D14B + X_Bit
XPlayIt_Pause		EQU	&4D14C + X_Bit
XPlayIt_Balance		EQU	&4D14D + X_Bit
XPlayIt_PauseAt		EQU	&4D14E + X_Bit
XPlayIt_VU		EQU	&4D14F + X_Bit
XPlayIt_ListDrivers	EQU	&4D150 + X_Bit
XPlayIt_Identify	EQU	&4D151 + X_Bit
XPlayIt_Queue		EQU	&4D152 + X_Bit
XPlayIt_SetLoop		EQU	&4D153 + X_Bit
XPlayIt_FileInfo	EQU	&4D154 + X_Bit
XPlayIt_ClientOp	EQU	&4D155 + X_Bit

		MACRO
		movpcip
		teq	r0,r0		; force at least one flag to be set (Z)
		teq	pc,pc		; see if we're in 32-bit mode
		movnes	pc,ip		; 26-bit (APCS-26/32) do movs pc,ip
		mov	pc,ip		; 32-bit (APCS-32 only) don't worry about flags
		MEND

; macro for returning a parameter (currently in register preg) for which the address of
; the location to store it is on the stack 'stack' words from sp (ie at sp+4*stack).

		MACRO
		RETPARS	$preg,$stack
		ldr	lr,[sp,#$stack*4]
		teq	lr,#0
		strne	$preg,[lr]
		MEND

; macro for returning a parameter (currently in register preg) for which the address of
; the location to store it is in areg.

		MACRO
		RETPARR	$preg,$areg
		teq	$areg,#0
		strne	$preg,[$areg]
		MEND


		AREA	|Playitv$$Code|,CODE,READONLY


; playit_error *xplayit_version(/*out*/int *version)

		EXPORT	xplayit_version
xplayit_version
		mov	ip,lr		; keep lr somewhere safe
		mov	r3,r0		; move return parameter out of the way
		swi	XPlayIt_Version
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r3		; if (r3) [r3]=r0
		mov	a1,#0		; set a1=0 for no error
stdret		movpcip			; return


; playit_error *xplayit_config_bits(/*in*/playit_configbits clear, playit_configbits xor,
;                                   /*out*/playit_configbits *newflags, playit_configbits *oldflags)

		EXPORT	xplayit_config_bits
xplayit_config_bits
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r2}	; move 1st return parameter out of the way
		mov	r2,r1		; set up parameters...
		mov	r1,r0		; ... for call to SWI
		mov	r0,#0		; reason = 0
		swi	XPlayIt_Config
		addvs	sp,sp,#4	; if error, purge stack...
		bvs	err_ret		; ...and return
		ldmfd	sp!,{lr}	; fetch 1st return par off stack
		RETPARR	r1,lr		; if (lr) [lr]=r1
		RETPARR	r2,r3		; if (r3) [r3]=r2
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_config_discbuffer(/*in*/int size, /*out*/int *oldsize)

		EXPORT 	xplayit_config_discbuffer
xplayit_config_discbuffer
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r1		; move return parameter out of the way
		mov	r1,r0		; set up registers for SWI
		mov	r0,#1		; reason = 1
		swi	XPlayIt_Config
		bvs	err_ret		; immediate exit if error
		RETPARR	r1,r2		; if (r2) [r2]=r1
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_config_echodelay(/*in*/int ms, /*out*/int *oldms)

		EXPORT	xplayit_config_echodelay
xplayit_config_echodelay
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r1		; move return parameter out of the way
		mov	r1,r0		; set up registers for SWI
		mov	r0,#2		; reason = 2
		swi	XPlayIt_Config
		bvs	err_ret		; immediate exit if error
		RETPARR	r1,r2		; if (r2) [r2]=r1
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_config_killbuffer(void)

		EXPORT 	xplayit_config_killbuffer
xplayit_config_killbuffer
		mov	ip,lr		; keep lr somewhere safe
		mov	r0,#3		; reason = 3
		swi	XPlayIt_Config
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_load_driver(/*in*/const char *name)

		EXPORT	xplayit_load_driver
xplayit_load_driver
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_LoadDriver
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_driver_info(/*out*/char **name, char **descr,
;                         char **version, int *framerate, int *mode)

		EXPORT	xplayit_driver_info
xplayit_driver_info
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r0-r3}	; all 5 parameters now on stack
		stmfd	sp!,{r4}	; have to preserve this
		swi	XPlayIt_DriverInfo
		bvs	xplayit_driver_info_X
		RETPARS	r0,1		; return 1st par if required
		RETPARS	r1,2		; return 2nd par if required
		RETPARS	r2,3		; return 3rd par if required
		RETPARS	r3,4		; return 4th par if required
		RETPARS	r4,5		; return 5th par if required
xplayit_driver_info_X
		ldmfd	sp!,{r4}
		add	sp,sp,#4*4	; purge parameters from stack
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_sample_info(char **name, playit_format *format,
;              int *framerate, int *bstart, int *bend, int *numframes)

		EXPORT	xplayit_sample_info
xplayit_sample_info
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r0-r3}     ; stick all parameters on stack
		stmfd	sp!,{r4-r5}	; store these cos we corrupt them
		swi	XPlayIt_SampleInfo
		bvs	xplayit_sample_info_x
		RETPARS	r0,2		; return 1st par if required
		RETPARS	r1,3		; return 2nd par if required
		RETPARS	r2,4		; return 3rd par if required
		RETPARS	r3,5		; return 4th par if required
		RETPARS	r4,6		; return 5th par if required
		RETPARS	r5,7		; return 6th par if required
xplayit_sample_info_x
		ldmfd	sp!,{r4-r5}	; restore r4 and r5
		add	sp,sp,#4*4	; purge rest of stack
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_status(playit_statusbits *status, playit_frame *frame)

		EXPORT	xplayit_status
xplayit_status
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r0		; keep 1st return in r2
		mov	r3,r1		; keep 2nd return in r3
		swi	XPlayIt_Status
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r2		; if (r2) [r2]=r0
		RETPARR	r1,r3		; if (r3) [r3]=r1
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_volume(int volume, int *oldvol)

		EXPORT	xplayit_volume
xplayit_volume
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_Volume
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r1		; if (r1) [r1]=r0
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_open(const char *filename, playit_format format,
;                       int framerate, int bstart, int bend, int auxpar);

		EXPORT	xplayit_open
xplayit_open
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r4-r5}
		add	lr,sp,#2*4	; point lr at original stack
		ldmia	lr,{r4-r5}	; get last two pars off stack
		swi	XPlayIt_Open
		ldmfd	sp!,{r4-r5}	; restore original r4,r5
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_open_block(playit_open_block *block)

		EXPORT	xplayit_open_block
xplayit_open_block
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r0,r4-r5}
		ldmia	r0,{r0-r5}	; load parameters from block
		swi	XPlayIt_Open
		ldmfd	sp!,{lr}	; get back paramater (ptr to block)
		stmia	lr,{r0-r5}	; write registers back to block
		ldmfd	sp!,{r4-r5}	; restore original r4,r5
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_open_autodetect(const char *filename)

		EXPORT	xplayit_open_autodetect
xplayit_open_autodetect
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r4-r5}	; save r4,r5 cos swi corrupts them
		mov	r1,#0		; force auto-detect mode
		swi	XPlayIt_Open
		ldmfd	sp!,{r4-r5}	; get back r4, r5
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_begin_end(playit_frame start, playit_frame end,
;                           playit_frame *rstart, playit_frame *rend);

		EXPORT	xplayit_begin_end
xplayit_begin_end
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_BeginEnd
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r2		; if (r2) [r2]=r0
		RETPARR	r1,r3		; if (r3) [r3]=r1
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_set_ptr(playit_frame frame, playit_frame *rframe)

		EXPORT	xplayit_set_ptr
xplayit_set_ptr
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_SetPtr
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r1		; if (r1) [r1]=r0
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_play(void)

		EXPORT	xplayit_play
xplayit_play
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_Play
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_stop(void);

		EXPORT	xplayit_stop
xplayit_stop
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_Stop
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_pause(void);

		EXPORT	xplayit_pause
xplayit_pause
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_Pause
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_balance(int balance, int *rbalance)

		EXPORT	xplayit_balance
xplayit_balance
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_Balance
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r1		; if (r1) [r1]=r0
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_pause_at(playit_frame frame, playit_frame *rframe)

		EXPORT	xplayit_pause_at
xplayit_pause_at
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_PauseAt
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r1		; if (r1) [r1]=r0
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_vu(int *left, int *right)

		EXPORT	xplayit_vu
xplayit_vu
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r0
		mov	r3,r1
		swi	XPlayIt_VU
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r2		; if (r2) [r2]=r0
		RETPARR	r1,r3		; if (r3) [r3]=r1
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_list_drivers(int reason, char *dir, void *buffer, int idx, int buffsize,
;                                          int *num_read, int *idx_out);

		EXPORT	xplayit_list_drivers
xplayit_list_drivers
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r4-r5}
		mov	r4,r3
		ldr	r5,[sp,#2*4]
		swi	XPlayIt_ListDrivers
		bvs	xplayit_list_drivers_X
		RETPARS	r3,3
		RETPARS	r4,4
xplayit_list_drivers_X
		ldmfd	sp!,{r4-r5}
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_identify(const char *filename, playit_format *format, int *framerate,
;                                      int *bstart, int *bend, int *auxpar, int *numframes)

		EXPORT	xplayit_identify
xplayit_identify
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r1-r3}	; all 6 return parameters now on stack
		stmfd	sp!,{r4-r6}	;
		swi	XPlayIt_Identify
		bvs	xplayit_identify_X
		RETPARR	r1,r3
		RETPARR	r2,r4
		RETPARR	r3,r5
		RETPARR	r4,r6
		RETPARR	r5,r7
		RETPARR	r6,r8
xplayit_identify_X
		ldmfd	sp!,{r4-r6}
		add	sp,sp,#3*4	; purge parameters
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_queue_add(const char *filename)

		EXPORT	xplayit_queue_add
xplayit_queue_add
		mov	ip,lr		; keep lr somewhere safe
		mov	r1,r0
		mov	r0,#0		; reason code=0
		swi	XPlayIt_Queue
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_queue_flush(void)

		EXPORT	xplayit_queue_flush
xplayit_queue_flush
		mov	ip,lr		; keep lr somewhere safe
		mov	r0,#1		; reason code=1
		swi	XPlayIt_Queue
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_set_loop(playit_frame start, playit_frame stop, int count,
;                                      playit_frame *rstart, playit_frame *rstop)

		EXPORT	xplayit_set_loop
xplayit_set_loop
		mov	ip,lr		; keep lr somewhere safe
		swi	XPlayIt_SetLoop
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r3		; if (r3) [r3]=r0
		RETPARS	r1,0		; if (par5) (*par5)=r1
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_file_info_format(char *filename, playit_sample_info *block)

		EXPORT	xplayit_file_info_format
xplayit_file_info_format
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r1
		mov	r1,r0		; shuffle registers as required
		mov	r0,#0		; reason code=0
		swi	XPlayIt_FileInfo
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_file_info_text(/*in*/char *filename, playit_text *block,
;                        int blocksize, playit_text_bits flags, /*out*/ int *nbytes);

		EXPORT	xplayit_file_info_text
xplayit_file_info_text
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r4}
		mov	r4,r3
		mov	r3,r2
		mov	r2,r1
		mov	r1,r0		; shuffle registers around
		mov	r0,#1		; reason code=1
		swi	XPlayIt_FileInfo
		bvs	xplayit_file_info_text_X
		RETPARS	r3,1		; if (par5) (*par5)=r3
xplayit_file_info_text_X
		ldmfd	sp!,{r4}
		movvc	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_file_info_filename(char **filename)

		EXPORT	xplayit_file_info_filename
xplayit_file_info_filename
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r0
		mov	r0,#2		; reason code=2
		swi	XPlayIt_FileInfo
		bvs	err_ret		; immediate exit if error
		RETPARR	r0,r2		; if (r2) [r2]=r0
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_clientop_register(/*in*/int flags, playit_eventbits events,
;                     /*out*/int **pollword)

		EXPORT	xplayit_clientop_register
xplayit_clientop_register
		mov	ip,lr
		mov	r3,r2		; keep this where we can get it later
		mov	r2,r1
		mov	r1,r0
		mov	r0,#0
		swi	XPlayIt_ClientOp
		bvs	err_ret		; immediate exit if error
		RETPARR	r2,r3		; if (r3) [r3]=r2
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return


; playit_error *xplayit_clientop_deregister(/*in*/int *pollword, /*out*/int *num_registered)

		EXPORT	xplayit_clientop_deregister
xplayit_clientop_deregister
		mov 	ip,lr
		mov	r3,r1		; keep return par in r3 for a bit
		mov	r2,r0		; move pollword to r2
		mov	r0,#1
		swi	XPlayIt_ClientOp
		bvs	err_ret		; immediate exit if error
		RETPARR	r1,r3		; if (r3) [r3]=r1
		mov	r0,#0		; set a1=0 for no error
		movpcip			; return

; return with V set (return address is in ip and V is set in CPSR)
err_ret
		teq	pc,pc		; note V not affected
		orrnes	pc,ip,#1<<28	; return if 26-bit mode - preserve most flags but set V
		mov	pc,ip

	END
